package GameObject;

import Army.ArmyEntity;
import Army.building.Building;
import Army.BuildingAndUnit;
import Army.Bullet;
import Army.PlayerTeam;
import Army.unit.Unit;
import Global.GlobalGameOption;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;

public class LayerManager {

	static ArrayList<Sprite> effects;
	private Map map;
	private ArrayList<Bullet> bullets;
	private PlayerTeam[] listTeam;
	private Building preBuilding;
	private Point viewPoint;
	private int viewWidth;
	private int viewHeight;
	private Rectangle limitBound;

	public LayerManager(int w, int h, int n) {
		viewWidth = w;
		viewHeight = h;
		effects = new ArrayList<>();
		limitBound = new Rectangle();
		bullets = new ArrayList<>();
		viewPoint = new Point(0, 0);
		listTeam = new PlayerTeam[n];
	}

	public PlayerTeam[] getListTeam() {
		return listTeam;
	}

	public Map getMap() {
		return map;
	}

	public void addEffect(Sprite sp) {
		effects.add(sp);
	}

	public void unitCollision(Unit army, Unit anotherArmy) {
		if (army != null && anotherArmy != null && army != anotherArmy && army.getBound().intersects(anotherArmy.getBound())) {
			Point vector = new Point(army.getPosition().x - anotherArmy.getPosition().x, army.getPosition().y - anotherArmy.getPosition().y);
			vector.x += Math.random() * 10 - 5;
			vector.y += Math.random() * 10 - 5;
			if (army.getState() != Unit.BuildingAndUnitState.RUN) {
				army.force(vector, 2);
			} else {
				army.force(vector, 1);
			}
			if (anotherArmy.getState() != Unit.BuildingAndUnitState.RUN) {
				anotherArmy.force(vector, -2);
			} else {
				anotherArmy.force(vector, -1);
			}

		}
	}

	public void buildingCollision(Unit army, Building anotherArmy) {
		if (army.getBound().intersects(anotherArmy.getBound())) {
			Point vector = new Point(army.getPosition().x - anotherArmy.getPosition().x, army.getPosition().y - anotherArmy.getPosition().y);

			vector.x += Math.random() * 10 - 5;
			vector.y += Math.random() * 10 - 5;

			army.force(vector, 4);
		}
	}

	public BufferedImage getMiniMap() {
		BufferedImage img = new BufferedImage(map.getMapCol(), map.getMapRow(), BufferedImage.TYPE_INT_ARGB);
		map.initItemMatrix();
		for (int i = 0; i < listTeam.length; i++) {
			for (int j = 0; j < listTeam[i].getListBuilding().size(); j++) {
				Building army = listTeam[i].getListBuilding().get(j);
				Point[] ps = getListMapCell(army);
				for (int k = 0; k < ps.length; k++) {
					Point p = ps[k];
					if (p.x >= 0 && p.x < img.getWidth()
							&& p.y >= 0 && p.y < img.getHeight()) {
						img.setRGB(p.x, p.y, ArmyEntity.TEAM_COLOR[army.getTeam()]);
						map.addItem(p.y, p.x, army.getTeam());
					}

				}
			}
			for (int j = 0; j < listTeam[i].getListUnit().size(); j++) {
				Unit army = listTeam[i].getListUnit().get(j);
				int x = army.getPosition().x / map.getCellWidth();
				int y = army.getPosition().y / map.getCellHeight();
				if (x >= 0 && x < img.getWidth()
						&& y >= 0 && y < img.getHeight()) {
					img.setRGB(x, y, ArmyEntity.TEAM_COLOR[army.getTeam()]);
				}
			}

		}


		int x = viewPoint.x / map.getCellWidth();
		int y = viewPoint.y / map.getCellHeight();
		int w = viewWidth / map.getCellWidth();
		int h = viewHeight / map.getCellHeight();
		img.getGraphics().drawRect(x - 1, y - 1, w + 2, h + 2);
		return img;
	}

	public void hitBullet(Bullet bullet) {
		for (int i = 0; i < listTeam.length; i++) {
			for (int j = 0; j < listTeam[i].getListUnit().size(); j++) {
				Unit armyEntity = listTeam[i].getListUnit().get(j);
				int r = armyEntity.getSize() / 2 + bullet.getSize() / 2;
				if (armyEntity.isAlive() && bullet.getTeam() != armyEntity.getTeam()
						&& Math.abs(bullet.getPosition().x - armyEntity.getPosition().x) < r
						&& Math.abs(bullet.getPosition().y - armyEntity.getPosition().y) < r) {

					effects.add(armyEntity.getHitedEffect(bullet.getPosition().x, bullet.getPosition().y));
					armyEntity.incHealthPoint(-getDamage(bullet.getDamage(), armyEntity.getArmorScore()));
					dieSound(armyEntity);
					setSound(bullet);
					bullet.detroy();
					break;

				}
			}

			for (int j = 0; j < listTeam[i].getListBuilding().size(); j++) {
				Building armyEntity = listTeam[i].getListBuilding().get(j);
				int r = armyEntity.getSize() / 2 + bullet.getSize() / 2;
				if (bullet.getTeam() != armyEntity.getTeam()
						&& Math.abs(bullet.getPosition().x - armyEntity.getPosition().x) < r
						&& Math.abs(bullet.getPosition().y - armyEntity.getPosition().y) < r) {

					effects.add(armyEntity.getHitedEffect(bullet.getPosition().x, bullet.getPosition().y));
					armyEntity.incHealthPoint(-getDamage(bullet.getDamage(), armyEntity.getArmorScore()));

					setSound(bullet);
					bullet.detroy();
					break;
				}

			}
		}
	}

	public void setSound(Bullet bullet) {
		String name;

		if (bullet.getPosition().x > viewPoint.x && bullet.getPosition().x < viewPoint.x + viewWidth && bullet.getPosition().y > viewPoint.y && bullet.getPosition().y < viewPoint.y + viewHeight) {
			double r = Math.random();
			if (r > 0.25) {
				name = "hit1";
			} else if (r > 0.5) {
				name = "hit2";
			} else if (r > 0.75) {
				name = "hit3";
			} else {
				name = "hit4";
			}
			GlobalGameOption.SOUND.getSound(name).start();

		}
	}

	int getDamage(int dam, int def) {
		return dam - (int) ((double) dam * def / 10.0 + 0.5);
	}

	public void setLimitBound(Rectangle bound) {
		limitBound = bound;
	}

	public void addBullet(Bullet bullet) {
		if (bullet != null) {
			bullets.add(bullet);
		}
	}

	public void setMap(Map map) {
		this.map = map;
	}

	public void setTeam(int i, PlayerTeam team) {
		listTeam[i] = team;
	}

	public Point getViewPoint() {
		return viewPoint;
	}

	public void move(int dx, int dy) {
		setViewPoint(viewPoint.x + dx, viewPoint.y + dy);
	}

	public void setViewPoint(Point position) {
		setViewPoint(position.x, position.y);
	}

	public void setViewPoint(int x, int y) {
		if (x < limitBound.x - 50) {
			x = limitBound.x - 50;
		} else if (x > limitBound.x + limitBound.width - viewWidth + 50) {
			x = limitBound.x + limitBound.width - viewWidth + 50;
		}
		if (y < limitBound.y - 50) {
			y = limitBound.y - 50;
		} else if (y > limitBound.y + limitBound.height - viewHeight + 50) {
			y = limitBound.y + limitBound.height - viewHeight + 50;
		}
		viewPoint.x = x;
		viewPoint.y = y;
	}

	public Point window2Local(Point p) {

		return new Point(p.x + viewPoint.x, p.y + viewPoint.y);
	}

	public Point local2Window(Point p) {
		return new Point(p.x - viewPoint.x, p.y - viewPoint.y);
	}

	public Point[] getListMapCell(BuildingAndUnit army) {
		int x = (army.getPosition().x - army.getSize() / 2 + map.getCellWidth() / 2) / map.getCellWidth();
		int y = (army.getPosition().y - army.getSize() / 2 + map.getCellHeight() / 2) / map.getCellHeight();
		int m = army.getSize() / map.getCellWidth();
		int n = army.getSize() / map.getCellHeight();
		if (m == 0) {
			m = 1;
		}
		if (n == 0) {
			n = 1;
		}
		Point[] ps = new Point[m * n];
		int k = 0;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				ps[k++] = new Point(x + j, y + i);
			}
		}
		return ps;
	}

	public void update() {

		for (Iterator<Sprite> it = effects.iterator(); it.hasNext();) {
			Sprite sprite = it.next();
			if (sprite.isLastFrame()) {
				it.remove();
			}
			sprite.nextFrame();
		}
		for (int i = 0; i < listTeam.length; i++) {
			listTeam[i].update();
		}

		for (Iterator<Bullet> it = bullets.iterator(); it.hasNext();) {
			Bullet bullet = it.next();
			if (bullet == null) {
				continue;
			}
			if (bullet.isIsDetroyed()) {
				it.remove();

			} else {
				bullet.update();
			}
		}
		unitAction();
		bulletAction();

	}

	private void bulletAction() {
		for (Iterator<Bullet> it = bullets.iterator(); it.hasNext();) {
			Bullet bullet = it.next();
			if (bullet != null && !bullet.isIsHited()) {
				hitBullet(bullet);
			}
		}
	}

	private void unitAction() {

		for (int i = 0; i < listTeam.length; i++) {
			for (int k = 0; k < listTeam[i].getListUnit().size(); k++) {

				Unit army = listTeam[i].getListUnit().get(k);
				if (army.isFired()) {
					bullets.add(army.getBullet());
				}
				for (int j = k; j < listTeam[i].getListUnit().size(); j++) {
					Unit anotherArmy = listTeam[i].getListUnit().get(j);
					unitCollision(army, anotherArmy);
				}
				collision(i, army);
				/*army.setLimit(limitBound.x + army.getSize() / 2, limitBound.y + army.getSize() / 2, limitBound.x + limitBound.width - army.getSize() / 2, limitBound.y + limitBound.height - army.getSize() / 2);*/

			}
		}

	}

	public void setPreBuilding(Building building) {
		preBuilding = building;
	}

	public void updatePreBuildingPosition(Point p) {
		if (preBuilding != null) {
			int x = (p.x - preBuilding.getSize() / 2 + map.getCellWidth() / 2) / map.getCellWidth();
			int y = (p.y - preBuilding.getSize() / 2 + map.getCellHeight() / 2) / map.getCellHeight();
			int m = preBuilding.getSize() / map.getCellWidth();
			int n = preBuilding.getSize() / map.getCellHeight();
			p.x = (x * map.getCellWidth() + m * map.getCellWidth() / 2);
			p.y = (y * map.getCellHeight() + n * map.getCellHeight() / 2);
			preBuilding.setPosition(p);
		}
	}

	public Building donePreBuilding() {
		if (preBuilding == null) {
			return null;
		}
		boolean flag = isBuildAble(preBuilding);
		if (flag) {
			Building building = preBuilding;
			preBuilding = null;
			return building;
		}
		return null;
	}

	public void draw(Graphics2D g2d) {

		map.draw(g2d, -viewPoint.x, -viewPoint.y);

		for (int i = 0; i < listTeam.length; i++) {
			listTeam[i].draw(g2d, -viewPoint.x, -viewPoint.y);
		}
		for (int i = 0; i < bullets.size(); i++) {
			Bullet bullet = bullets.get(i);
			if (bullet != null) {
				bullet.draw(g2d, -viewPoint.x, -viewPoint.y);
			}
		}
		for (int i = 0; i < effects.size(); i++) {
			Sprite sprite = effects.get(i);
			sprite.draw(g2d, -viewPoint.x, -viewPoint.y);
		}

		if (preBuilding != null) {
			g2d.setTransform(new AffineTransform());
			Point[] ps = getListMapCell(preBuilding);
			for (int i = 0; i < ps.length; i++) {
				int x = ps[i].x;
				int y = ps[i].y;
				if (map.isBuildAble(y, x)) {
					g2d.setColor(new Color(0, 255, 0, 128));
				} else {
					g2d.setColor(new Color(255, 0, 0, 128));
				}
				g2d.fillRect(x * map.getCellWidth() - viewPoint.x + 1, y * map.getCellHeight() - viewPoint.y + 1, map.getCellWidth() - 2, map.getCellHeight() - 2);
			}
			preBuilding.draw(g2d, -viewPoint.x, -viewPoint.y);
		}
	}

	protected void collision(int i, Unit army) {

		for (int j = i + 1; j < listTeam.length; j++) {
			for (int k = 0; k < listTeam[j].getListUnit().size(); k++) {
				Unit anotherArmy = listTeam[j].getListUnit().get(k);
				unitCollision(army, anotherArmy);
			}
		}
		teriantColision(army);
	}

	protected void teriantColision(Unit army) {

		int jcell = army.getPosition().x / map.getCellWidth();
		int icell = army.getPosition().y / map.getCellHeight();

		if (!map.isBuildAble(icell, jcell)) {
			int dx = 0, dy = 0;
			int d = map.getCellWidth() + 1;
			if (map.isBuildAble(icell - 1, jcell)) {
				d = army.getPosition().y - icell * map.getCellHeight();
				dy = Math.max(-d - 1, -5);

			}
			if (map.isBuildAble(icell + 1, jcell)) {
				int newD = (icell + 1) * map.getCellHeight() - army.getPosition().y;
				if (newD < d) {
					d = newD;
					dy = Math.min(d + 1, 5);
				}
			}
			if (map.isBuildAble(icell - 1, jcell - 1)) {
				int newDy = army.getPosition().y - icell * map.getCellHeight();
				int newDx = army.getPosition().x - jcell * map.getCellWidth();
				if (newDx + newDy < d) {
					d = newDx + newDy;
					dy = Math.max(-newDx - 1, -5);
					dx = Math.max(-newDy - 1, -5);
				}
			}
			if (map.isBuildAble(icell - 1, jcell + 1)) {
				int newDy = army.getPosition().y - icell * map.getCellHeight();
				int newDx = (jcell + 1) * map.getCellWidth() - army.getPosition().x;
				if (newDx + newDy < d) {
					d = newDx + newDy;
					dy = Math.max(-newDx - 1, -5);
					dx = Math.min(newDy + 1, 5);
				}
			}
			if (map.isBuildAble(icell + 1, jcell - 1)) {
				int newDy = (icell + 1) * map.getCellHeight() - army.getPosition().y;
				int newDx = army.getPosition().x - jcell * map.getCellWidth();
				if (newDx + newDy < d) {
					d = newDx + newDy;
					dy = Math.min(newDx + 1, 5);
					dx = Math.max(-newDy - 1, -5);
				}
			}
			if (map.isBuildAble(icell + 1, jcell + 1)) {
				int newDy = (icell + 1) * map.getCellHeight() - army.getPosition().y;
				int newDx = (jcell + 1) * map.getCellWidth() - army.getPosition().x;
				if (newDx + newDy < d) {
					d = newDx + newDy;
					dy = Math.min(newDx + 1, 5);
					dx = Math.min(newDy + 1, 5);
				}
			}
			if (map.isBuildAble(icell, jcell - 1)) {
				int newD = army.getPosition().x - jcell * map.getCellWidth();
				if (newD < d) {
					d = newD;
					dx = Math.max(-d - 1, -5);
					dy = 0;
				}
			}
			if (map.isBuildAble(icell, jcell + 1)) {
				int newD = (jcell + 1) * map.getCellWidth() - army.getPosition().x;
				if (newD < d) {
					d = newD;
					dx = Math.min(d + 1, 5);
					dy = 0;
				}
			}
			if (d == map.getCellWidth() + 1) {
				army.move(5, 5);
			} else {
				army.move(dx, dy);
				findPath(army, dy, dx);
			}


		}
	}

	protected void findPath(Unit army, int dy, int dx) {
		if (army.getCurrentTarget() != null && army.getState() == Unit.BuildingAndUnitState.RUN) {
			int ydir = army.getCurrentTarget().y - army.getPosition().y;
			int xdir = army.getCurrentTarget().x - army.getPosition().x;
			int dir = -1;
			int way = 1;

			if (dy != 0 && dx != 0 && Math.random() > 0.5) {
				dir = 1;
			} else if (dx == 0) {
				dir = 1;
				way = -1;
			} else if (dy == 0) {
				dir = -1;
			}
			if (Math.random() > 0.9) {
				way = -1;
			}
			if (dir == 1) {
				if (xdir >= 0) {
					army.setDodgePoint(dir, -way, map.getCellWidth() + 1);
				} else {
					army.setDodgePoint(dir, way, map.getCellWidth() + 1);
				}
			} else {
				if (ydir >= 0) {
					army.setDodgePoint(dir, way, map.getCellHeight() + 1);
				} else {
					army.setDodgePoint(dir, -way, map.getCellHeight() + 1);
				}
			}
		}
	}

	public boolean isBuildAble(Building building) {
		boolean flag = true;
		Point[] ps = getListMapCell(building);
		for (int i = 0; i < ps.length; i++) {
			int x = ps[i].x;
			int y = ps[i].y;
			if (!map.isBuildAble(y, x)) {
				flag = false;
			}
		}
		return flag;
	}

	public void dieSound(Unit armyEntity) {
		if (!armyEntity.isAlive() && armyEntity.getPosition().x > viewPoint.x && armyEntity.getPosition().x < viewPoint.x + viewWidth && armyEntity.getPosition().y > viewPoint.y && armyEntity.getPosition().y < viewPoint.y + viewHeight) {
			double random = Math.random();
			if (random > 0.9) {
				GlobalGameOption.SOUND.getSound("scream").start();
			}
		}
	}
}
